<?php
/* 
 * Copyright (c) 2018-2021   All rights reserved.
 * 
 * 创建时间：2021-08-31 14:52
 *
 * 项目：rm  -  $  - Payment.php
 *
 * 作者：liwei 
 */

namespace modules\levpays\modules\alipay\sdk;

use AlipayTradePagePayRequest;
use AlipayTradeQueryContentBuilder;
use AlipayTradeService;
use AlipayTradeWapPayContentBuilder;
use AopClient;
use Lev;
use lev\base\Controllerv;
use lev\helpers\UrlHelper;
use modules\levpays\levpaysHelper;
use modules\levpays\table\tradesHelper;

!defined('INLEV') && exit('Access Denied LEV');

require_once __DIR__.DIRECTORY_SEPARATOR.'sdk/wappay/service/AlipayTradeService.php';

class Payment
{

    public static $instance = null, $config = null;

    public static function loadConfig() {
        if (isset(static::$config)) return static::$config;

        static::$config = [
            'app_id'               => Lev::stget('app_id', 'alipay'),// 商户号，假定为`1000100`
            'alipay_public_key'    => trim(Lev::stget('alipay_public_key', 'alipay')), //平台证书
            'merchant_private_key' => trim(Lev::stget('merchant_private_key', 'alipay')), //商户私钥
            //异步通知地址
            'notify_url' => Lev::$aliases['@siteurl'].'/levpays_alipay_notify.php',

            //同步跳转
            'return_url' => Lev::$aliases['@siteurl'].'/levpays_alipay_return.php',

            //编码格式
            'charset'    => "UTF-8",

            //签名方式
            'sign_type'  => "RSA2",

            //支付宝网关
            'gatewayUrl' => "https://openapi.alipay.com/gateway.do",

        ];
        (empty(static::$config['app_id']) || empty(static::$config['alipay_public_key'])) && is_file($file = __DIR__ . '/_lev.config.php') &&
        static::$config = include $file;
        return static::$config;
    }

    public static function setAopClient($miniAppid = '') {
        static::loadConfig();

        $aop = new AopClient ();
        $aop->gatewayUrl         = static::$config['gatewayUrl'];
        $aop->appId              = $miniAppid ?: static::$config['app_id'];
        $aop->rsaPrivateKey      = static::$config['merchant_private_key'];//'请填写开发者私钥去头去尾去回车，一行字符串';
        $aop->alipayrsaPublicKey = static::$config['alipay_public_key'];//'请填写支付宝公钥，一行字符串';
        $aop->apiVersion         = '1.0';
        $aop->signType           = 'RSA2';
        $aop->postCharset        = static::$config['charset'];//;
        $aop->format             = 'json';

        return $aop;
    }

    public static function wapPay($out_trade_no, $subject, $total_amount, $body = '', $timeout_express = '1m') {
        require_once __DIR__.DIRECTORY_SEPARATOR.'sdk/wappay/buildermodel/AlipayTradeWapPayContentBuilder.php';

        $config = static::loadConfig();
        if ($out_trade_no){
//            //商户订单号，商户网站订单系统中唯一订单号，必填
//            $out_trade_no = $_POST['WIDout_trade_no'];
//
//            //订单名称，必填
//            $subject = $_POST['WIDsubject'];
//
//            //付款金额，必填
//            $total_amount = $_POST['WIDtotal_amount'];
//
//            //商品描述，可空
//            $body = $_POST['WIDbody'];
//
//            //超时时间
//            $timeout_express="1m";

            $payRequestBuilder = new AlipayTradeWapPayContentBuilder();
            $payRequestBuilder->setBody($body);
            $payRequestBuilder->setSubject($subject);
            $payRequestBuilder->setOutTradeNo($out_trade_no);
            $payRequestBuilder->setTotalAmount($total_amount);
            $payRequestBuilder->setTimeExpress($timeout_express);

            $payResponse = new AlipayTradeService($config);
            $result=$payResponse->wapPay($payRequestBuilder,$config['return_url'],$config['notify_url']);

            return ;
        }
    }

    public static function pcPay($out_trade_no, $subject, $total_amount, $body = '', $timeout_express = '1m') {
        require_once __DIR__ . '/sdk/aop/AopClient.php';

        require_once __DIR__ . '/sdk/aop/request/AlipayTradePagePayRequest.php';

        $config = static::loadConfig();


        /** 初始化 **/

        $aop = new AopClient ();



        /** 支付宝网关 **/

        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';



        /** 应用id,如何获取请参考：https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/

        $aop->appId = static::$config['app_id'];



        /** 密钥格式为pkcs1，如何获取私钥请参考：https://opensupport.alipay.com/support/helpcenter/207/201602469554  **/

        $aop->rsaPrivateKey = static::$config['merchant_private_key'];



        /** 支付宝公钥，如何获取请参考：https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/

        $aop->alipayrsaPublicKey = static::$config['alipay_public_key'];



        /** 签名算法类型 **/

        $aop->signType = static::$config['sign_type'];



        /** 请求使用的编码格式 **/

        $aop->postCharset = static::$config['charset'];



        /** 仅支持JSON  **/

        $aop->format = 'json';



        /** 实例化具体API对应的request类，类名称和接口名称对应，当前调用接口名称：alipay.trade.page.pay（电脑网站支付） **/

        $request = new  AlipayTradePagePayRequest ();



        /** 设置业务参数 **/

        $request->setBizContent("{" .

            /** 商户订单号,商户自定义，需保证在商户端不重复，如：20200612000001 **/

            "\"out_trade_no\":\"{$out_trade_no}\"," .



            /** 销售产品码,固定值：FAST_INSTANT_TRADE_PAY **/

            "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"," .



            /** 订单金额，精确到小数点后两位 **/

            "\"total_amount\":\"{$total_amount}\"," .



            /** 订单标题 **/

            "\"subject\":\"{$subject}\"," .



            /** 业务扩展参数 **/

            //"\"extend_params\":{" .



            /** 花呗分期参数传值前提：必须有该接口花呗收款准入条件，且需签约花呗分期 **/

            /** 指定可选期数，只支持3/6/12期，还款期数越长手续费越高 **/

            // "\"hb_fq_num\":\"3\"," .



            /** 指定花呗分期手续费承担方式，手续费可以由用户全承担（该值为0），也可以商户全承担（该值为100），但不可以共同承担，即不可取0和100外的其他值。 **/

            //"\"hb_fq_seller_percent\":\"100\"" .

            //  "}," .

            /** 订单描述 **/

            "\"body\":\"{$body}\"" .

            "}");



        /** 注：支付结果以异步通知为准，不能以同步返回为准，因为如果实际支付成功，但因为外力因素，如断网、断电等导致页面没有跳转，则无法接收到同步通知；**/

        /** 支付完成的跳转地址,用于用户视觉感知支付已成功，传值外网可以访问的地址，如果同步未跳转可参考该文档进行确认：https://opensupport.alipay.com/support/helpcenter/193/201602474937 **/

        $request->setReturnUrl(static::$config['return_url']);



        /** 异步通知地址，以http或者https开头的，商户外网可以post访问的异步地址，用于接收支付宝返回的支付结果，如果未收到该通知可参考该文档进行确认：https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/

        $request->setNotifyUrl(static::$config['notify_url']);



        /** 调用SDK生成form表单 **/

        $result = $aop->pageExecute ($request);

        //$reponse = $aop->Execute($request);



        /** 调用SDK生成支付链接，可在浏览器打开链接进入支付页面 **/

//$result = $aop->pageExecute ($request,'get');



        /** 第三方调用（服务商模式），传值app_auth_token后，会收款至授权token对应商家账号，如何获传值app_auth_token请参考文档：https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/

//$result = $aop->pageExecute($request,'get',"传入获取到的app_auth_token值");



        /** 获取接口调用结果，如果调用失败，可根据返回错误信息到该文档寻找排查方案：https://opensupport.alipay.com/support/helpcenter/97 **/

        print_r(($result));exit;
    }

    public static function ReturnUrl() {

        $config = static::loadConfig();

        $arr = $_GET;
        unset($arr['id'], $arr['r']);
        isset($arr['#id']) && $arr['id'] = $arr['#id'];
        isset($arr['#r']) && $arr['r'] = $arr['#r'];
        $alipaySevice = new AlipayTradeService($config);
        $result = $alipaySevice->check($arr);

        /* 实际验证过程建议商户添加以下校验。
        1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        if($result) {//验证成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //请在这里加上商户的业务逻辑程序代码

            //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
            //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表

            //商户订单号

            //$out_trade_no = htmlspecialchars($_GET['out_trade_no']);

            //支付宝交易号

            //$trade_no = htmlspecialchars($_GET['trade_no']);

            //echo "验证成功<br />外部订单号：".$out_trade_no;

            //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            echo "验证成功";
            Controllerv::redirect(UrlHelper::toModule('levpays'));
        } else {
            //验证失败
            echo "验证失败";
            //Controllerv::redirect(Lev::toReRoute(['/', 'id'=>'levpays']));
            Controllerv::redirect(UrlHelper::toModule('levpays'));
            //print_r($arr);
            //print_r($alipaySevice);
            //print_r($result);
        }
    }

    public static function payNotify()
    {
        /* *
 * 功能：支付宝服务器异步通知页面
 * 版本：2.0
 * 修改日期：2016-11-01
 * 说明：
 * 以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。

 *************************页面功能说明*************************
 * 创建该页面文件时，请留心该页面文件中无任何HTML代码及空格。
 * 该页面不能在本机电脑测试，请到服务器上做测试。请确保外部可以访问该页面。
 * 如果没有收到该页面返回的 success 信息，支付宝会在24小时内按一定的时间策略重发通知
 */
        $config = static::loadConfig();

        $arr = $_POST;
        $alipaySevice = new AlipayTradeService($config);
        $alipaySevice->writeLog(var_export($_POST,true));
        $result = $alipaySevice->check($arr);

        /* 实际验证过程建议商户添加以下校验。
        1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        if($result) {//验证成功
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //请在这里加上商户的业务逻辑程序代


            //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

            //获取支付宝的通知返回参数，可参考技术文档中服务器异步通知参数列表

            //商户订单号

            $out_trade_no = $_POST['out_trade_no'];

            //支付宝交易号

            $trade_no = $_POST['trade_no'];

            //交易状态
            $trade_status = $_POST['trade_status'];


            if($_POST['trade_status'] == 'TRADE_FINISHED') {

                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
                //如果有做过处理，不执行商户的业务程序

                //注意：
                //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
            }
            else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
                //如果有做过处理，不执行商户的业务程序
                //注意：
                //付款完成后，支付宝系统发送该交易状态通知
            }
            //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

            echo "success";		//请不要修改或删除

        }else {
            //验证失败
            echo "fail";	//请不要修改或删除

        }

    }

    public static function checkTradeNo($tradeNo, $alipayTradeNo = '') {
        return aliminiPay::queryTrade($tradeNo, $alipayTradeNo);

//        require_once __DIR__.DIRECTORY_SEPARATOR.'sdk/wappay/buildermodel/AlipayTradeQueryContentBuilder.php';
//        if ($tradeNo || $alipayTradeNo){
//            static::loadConfig();
//
//            //商户订单号和支付宝交易号不能同时为空。 trade_no、  out_trade_no如果同时存在优先取trade_no
//            //商户订单号，和支付宝交易号二选一
//            $out_trade_no = $tradeNo;//trim($_POST['WIDout_trade_no']);T0000000001630467113gT0000000001630566209
//
//            //支付宝交易号，和商户订单号二选一
//            $trade_no = $alipayTradeNo;//trim($_POST['WIDtrade_no']);
//
//            $RequestBuilder = new AlipayTradeQueryContentBuilder();
//            $RequestBuilder->setTradeNo($trade_no);
//            $RequestBuilder->setOutTradeNo($out_trade_no);
//
//            $Response = new AlipayTradeService(static::$config);
//            $result = (array)$Response->Query($RequestBuilder);
//            $result['_paySuccess'] = $result['trade_status'] == 'TRADE_SUCCESS' || $result['trade_status'] == 'TRADE_FINISHED';
//            return $result;
//        }
//        return false;
    }

    public static function paySuccess(array $msg, $tradeNo, $pre, array $outTradeInfo)
    {
        static::loadConfig();
        static::$config['openidField'] = 'alipayuserid';
        static::$config['paytypeid']   = 1;
        static::$config['appid']       = static::$config['app_id'];
        //static::$config['mchid'] = static::$config['mchid'];

        $outTradeInfo['openid']         = $outTradeInfo['buyer_user_id'];
        $outTradeInfo['transaction_id'] = $outTradeInfo['trade_no'];
        $outTradeInfo['appid']          = static::$config['appid'];//$outTradeInfo['buyer_user_id'];
        $outTradeInfo['mchid']          = '';
        $outTradeInfo['success_time']   = $outTradeInfo['send_pay_date'];

        levpaysHelper::paySuccess($msg, $tradeNo, $pre, $outTradeInfo, static::$config);
    }
}